/// Text Overlay Application: Expressions Class
/// This Class contains all common expression used in different places of the applications
/// this expressions help extract information from strings and tags, transform values and 
/// handle strings.

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.IO;

namespace TextOverlay
{
    public struct CExpressions
    {
        public Regex getinteger ; 
        public Regex getstring ; 
        public string answer;

        /// <summary>
        /// This is a collection of Regular Expressions used in the application
        /// </summary>
        /// <param name="value"></param>
        public CExpressions(bool value)
        {
            getinteger = new Regex(@"\-?\d+", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            getstring = new Regex(@"(\x22\w+\,?\w+?\x22)", RegexOptions.IgnoreCase | RegexOptions.Compiled );

            diff = 0;
            minutes = 0;
            hours = 0;
            seconds = 0;
            Time = "";
            chars = new char[2];
            chars[0] = Convert.ToChar("\"");
            chars[1] = Convert.ToChar(",");
            answer = "";
            wasNumber = 0;
        }


        /// <summary>
        /// Finds a tag in string and replaces its value with a new one. If the target
        /// tag does not exist in the string, this function creates the tag.
        /// </summary>
        /// <param name="Base">The base string</param>
        /// <param name="OldTag">The tag to be replaced in the base</param>
        /// <param name="NewTag">The new value of the tag</param>
        /// <returns></returns>
        public string ReplaceTag(string Base, string OldTag, string NewTag)
        {
            try
            {
                int start = Base.IndexOf(OldTag);
                if (start != -1)
                {
                    int end = Base.IndexOf("\"", start + OldTag.Length);
                    if (end != -1 && end != start)
                        return Base.Replace(Base.Substring(start, (end - start)  + 1), NewTag);
                    else
                        return (Base + ", " + NewTag + ", ");
                }
                return (Base + ", " + NewTag + ", ");
            }
            catch
            {
                return Base;
            }
        }

        /// <summary>
        /// This function retrieves the Font tag from a detail string
        /// </summary>
        /// <param name="detail">the detail string</param>
        /// <returns>the value of the font tag</returns>
        public string GetFontFace(string detail)
        {
            try
            {
                int start = detail.IndexOf("FONT=\"");
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + 6);
                    answer = detail.Substring(start + 6, end - (start + 6));
                    return answer;
                }
                return "";
            }
            catch
            {
                return "";
            }
        }

        /// <summary>
        /// This function retrieves the Font Color tag from a detail string
        /// </summary>
        /// <param name="detail">the detail string</param>
        /// <returns>the value of font color tag</returns>
        public string GetFontColorTag(string detail)
        {
            try
            {
                int start = detail.IndexOf("[COLOR~VAL=\"");
                if (start < 0) start = detail.IndexOf("[color~val=\"");
                if (start < 0) start = detail.IndexOf("[Color~Val=\"");
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + 12);
                    answer = detail.Substring(start + 12, end - (start + 12));
                    if (answer.ToUpper() == "BLACK")
                        return "#030303";
                    if (answer.ToUpper() == "TRANSPARENT" || answer.ToUpper() == "ALPHA")
                        return "#000000";
                    return answer;
                }
                return "";
            }
            catch
            {
                return "";
            }
        }

        /// <summary>
        /// This function retrieves the Font tag from a detail string
        /// </summary>
        /// <param name="detail">the detail string</param>
        /// <returns>the value of the font tag</returns>
        public string GetFontTag(string detail)
        {           
            try
            {
                int start = detail.IndexOf("[FONT~VAL=\"");
                if (start < 0) start = detail.IndexOf("[font~val=\"");
                if (start < 0) start = detail.IndexOf("[Font~Val=\"");
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + 11);
                    answer = detail.Substring(start + 11, end - (start + 11)).Replace("~", " ");
                    return answer;
                }
                return "";
            }
            catch
            {
                return "";
            }
        }

        /// <summary>
        /// This function retrieves the background color tag from a detail string
        /// </summary>
        /// <param name="detail">the detail string</param>
        /// <returns>the value of the requested tag</returns>
        public string GetBgColorTag(string detail)
        {
            try
            {
                int start = detail.IndexOf("[BGCOLOR~VAL=\"");
                if (start < 0) start = detail.IndexOf("[bgcolor~val=\"");
                if (start < 0) start = detail.IndexOf("[Bgcolor~Val=\"");
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + 14);
                    answer = detail.Substring(start + 14, end - (start + 14));
                    return answer;
                }
                return "";
            }
            catch
            {
                return "white";
            }
        }

        /// <summary>
        /// This function retrieves the background image tag from a detail string
        /// </summary>
        /// <param name="detail">the detail string</param>
        /// <returns>the value of the requested tag</returns>
        public string GetBgImgTag(string detail)
        {
            try
            {
                int start = detail.ToUpper().IndexOf("[BGIMAGE~VAL=\"");
                if (start < 0) start = detail.IndexOf("[bgimage~val=\"");
                if (start < 0) start = detail.IndexOf("[Bgimage~Val=\"");
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + 14);
                    answer = detail.Substring(start + 14, end - (start + 14));
                    return answer;
                }
                return "";
            }
            catch
            {
                return "";
            }
        }

        /// <summary>
        /// This function retrieves the background color tag from a detail string
        /// </summary>
        /// <param name="detail">the detail string</param>
        /// <returns>the value of the requested tag</returns>
        public System.Drawing.Color ReadBackColor(string detail)
        {
            try
            {
                int start = detail.IndexOf("BGKEY=\"");
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + 7);
                    answer = detail.Substring(start + 7, end - (start + 7));
                    if (answer.StartsWith("#"))
                        return HexToRGB(answer);
                    else
                        return System.Drawing.Color.FromName(answer);
                }
                return System.Drawing.Color.Black;
            }
            catch
            {
                return System.Drawing.Color.Black;
            }
        }

        /// <summary>
        /// This function retrieves the background image tag from a detail string
        /// </summary>
        /// <param name="detail">the detail string</param>
        /// <returns>the value of the requested tag</returns>
        public int ReadBackImage(string detail)
        {
            try
            {
                int start = detail.IndexOf("BGIMAGE=\"");
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + 9);
                    answer = detail.Substring(start + 9, end - (start + 9));
                    if (answer.Length > 0)
                        return Convert.ToInt32(answer);
                }
                return -1;
            }
            catch
            {
                return -1;
            }
        }

        /// <summary>
        /// This function retrieves the revealin tag from a detail string
        /// </summary>
        /// <param name="detail">the detail string</param>
        /// <returns>the value of the requested tag</returns>
        public string ReadRevealIn(string detail)
        {
            try
            {
                int start = detail.IndexOf("REVEALIN=\"");
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + 10);
                    answer = detail.Substring(start + 10, end - (start + 10));
                    if (answer.Length > 0)
                        return answer;
                }
                return "";
            }
            catch
            {
                return "";
            }
        }

        /// <summary>
        /// This function retrieves the Font Color tag from a detail string
        /// </summary>
        /// <param name="detail">the detail string</param>
        /// <returns>the value of the requested tag</returns>
        public System.Drawing.Color ReadFontColor(string detail)
        {
            try
            {
                int start = detail.IndexOf("COLOR=\"");
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + 7);
                    answer = detail.Substring(start + 7, end - (start + 7));
                    if (answer.Length > 0)
                    {
                        if (answer.StartsWith("#"))
                            return HexToRGB(answer);
                        else if (isNumeric(answer.Substring(0, 1)))
                            return StrToRGB(answer);
                        else
                            return System.Drawing.Color.FromName(answer);
                    }
                }
                return System.Drawing.Color.White;
            }
            catch
            {
                return System.Drawing.Color.White;
            }


        }

        /// <summary>
        /// Converts from a string formated (##,##,##) to a System.Drawing.Color
        /// </summary>
        /// <param name="str">string formated (##,##,##)</param>
        /// <returns>a System.Drawing.Color</returns>
        public System.Drawing.Color StrToRGB(string str)
        {
            return System.Drawing.Color.FromArgb(GetIntValue(str, 0), GetIntValue(str, 1), GetIntValue(str, 2));
        }

        /// <summary>
        /// Converts from a string formated (#000000) to a System.Drawing.Color
        /// </summary>
        /// <param name="hex">string formated (#000000)</param>
        /// <returns>a System.Drawing.Color</returns>
        public System.Drawing.Color HexToRGB(string hex)
        {
            int R = Convert.ToInt32(hex.Substring(1, 2), 16);
            int G = Convert.ToInt32(hex.Substring(3, 2), 16);
            int B = Convert.ToInt32(hex.Substring(5, 2), 16);
            return System.Drawing.Color.FromArgb(R, G, B);
        }

        /// <summary>
        /// Retrieves a integer value from a string formated Value="00" or Value="00,00"
        /// </summary>
        /// <param name="detail">string formated Value="00" or Value="00,00"</param>
        /// <param name="index">index of the number value</param>
        /// <returns>integer value</returns>
        public int GetIntValue(string detail, int index)
        {
            if (detail != null)
            {
                MatchCollection match = getinteger.Matches(detail);
                if (match.Count > index)
                    return Convert.ToInt32(match[index].Value);
                return 0;
            }
            else
                return 0;
        }

        /// <summary>
        /// Retrieves a string value from a string formated Value="this"
        /// </summary>
        /// <param name="detail">string formated Value="this"</param>
        /// <returns>string value</returns>
        public string GetStringValue(string detail)
        {
            int start = detail.IndexOf("\"");
            int end = detail.IndexOf("\"", start + 1);
            if (end > 0)
                return detail.Substring(start + 1, end - (start + 1));
            else
                return "";
        }

        char[] chars;
        /// <summary>
        /// Retrieves a integer value from a string formated Value="00"
        /// </summary>
        /// <param name="detail">string formated Value="00"</param>
        /// <returns>integer value</returns>
        public int GetIntValue(string detail)
        {
            int start = detail.IndexOf("\"");

            if (start < 0)
            {
                int val = GetIntValue(detail, 0);
                return val;
            }

            int end = detail.IndexOfAny(chars, start + 1);
            if (end > 0)
                return Convert.ToInt32(detail.Substring(start + 1, end - (start + 1)));
            else
            {
                if (isNumeric(detail))
                    return Convert.ToInt32(detail);
            }
            return 0;
        }

        /// <summary>
        /// Retrieves a string value from a string formated Value="this"
        /// </summary>
        /// <param name="detail">string formated Value="this"</param>
        /// <returns>string value</returns
        public string GetStringValueEx(string detail)
        {
            Match match = getstring.Match(detail);
            if (match.Success)
                return match.Value.Substring(1, match.Value.Length - 2);
            else
            {
                if(detail.Length > 0)
                return detail.Replace("\"", "");
            }
                return "";
        }

        /// <summary>
        /// Retrieves a string value from a string formated Value="this"
        /// </summary>
        /// <param name="detail">string formated Value="this"</param>
        /// <returns>string value</returns
        public string GetStringValue(string detail, string separator, int index)
        {
            int counter = 0;
            foreach (string word in GetStringValueEx(detail).Split(Convert.ToChar(separator)))
            {
                if (counter == index)
                    return word;
                counter++;
            }
            return "";
        }

        /// <summary>
        /// Converts a string containing a time value formatted hh:mm:ss/frames to its value in frames
        /// </summary>
        /// <param name="fromTime">Time string</param>
        /// <param name="fps">Frames per second</param>
        /// <returns>frame equivalent</returns>
        public int TimeToFrame(string fromTime, int fps)
        {
            int toFrame = (Convert.ToInt32(fromTime.Substring(0, 2)) * (216000)) + (Convert.ToInt32(fromTime.Substring(3, 2)) * (3600)) + (Convert.ToInt32(fromTime.Substring(6, 2)) * 60) + Convert.ToInt32(fromTime.Substring(9)) * (60 / fps);
            return toFrame;
        }

        int diff, hours, minutes, seconds;
        string Time;
        /// <summary>
        /// Converts a frame number to its equivalent in time
        /// </summary>
        /// <param name="fromFrame">frame</param>
        /// <param name="fps">frames per second</param>
        /// <returns>time value formatted hh:mm:ss</returns>
        public string FrameToTime(int fromFrame, int fps)
        {
            //if (fcounter > 59)
            //{
                hours = fromFrame / 216000;
                diff = fromFrame - (hours * 216000);
                minutes = diff / 3600;
                diff = diff - (minutes * 3600);
                seconds = diff / 60;
                Time = String.Format("{0:00}:{1:00}:{2:00}", hours, minutes, seconds);
                return Time;
            //}
            //else
            //{
            //    fcounter++;
            //    return Time;
            //}
            
        }


        public string FrameToTime(int frames)
        {
            DateTime Base = DateTime.Parse("00:00:00");
            return Base.AddSeconds(frames / 60).ToString("HH:MM:");
        }

        /// <summary>
        /// Slipts a string into words using the space character as separator
        /// </summary>
        /// <param name="LongString">The string to be separated in words</param>
        /// <param name="Array">a List collection of string where the words will be stored</param>
        public void SliptString(string LongString, List<string> Array)
        {
            int start = 0;
            int stop = 0;
            Array.Clear();
            while (true)
            {
                stop = LongString.IndexOf(" ", start);
                if (stop < 0)
                {
                    Array.Add(LongString.Substring(start, LongString.Length - start));
                    return;
                }
                else
                {
                    Array.Add(LongString.Substring(start, stop - start));
                    start = stop + 1;
                }
            }
        }

        /// <summary>
        /// Splits a string into fragments of a given amount of characters
        /// </summary>
        /// <param name="LongString">The string to be split</param>
        /// <param name="Array">a List collection of string where the words will be stored</param>
        /// <param name="size">the size of the fragments in characters</param>
        public void BreakString(String LongString, List<string> Array, int size)
        {
            Array.Clear();
            int Indice = 0;
            try
            {
                while (true)
                {
                    if (LongString.Length >= (Indice + size))
                    {
                        Array.Add(LongString.Substring(Indice, size));
                        Indice += size;
                    }
                    else
                    {
                        if(LongString.Length > Indice)
                            Array.Add(LongString.Substring(Indice));
                        break;
                    }
                }

            }
            catch
            {
                Track.LogInfo("Error Breaking String"); 
            }
            return;
        }


        /// <summary>
        /// Retrieves a given tag from string
        /// </summary>
        /// <param name="tag">Tag to be retrieved</param>
        /// <param name="detail">String where to find the tag</param>
        /// <returns>string value of the tag</returns>
        public string GetDataTag(string tag, string detail)
        {
            try
            {   
                answer = "";
                int start = detail.IndexOf(tag);
                if (start != -1)
                {
                    int end = detail.IndexOf("\"", start + tag.Length);
                    if (end > -1)
                        answer = detail.Substring(start + tag.Length, end - (start + tag.Length));
                }
                return answer;
            }
            catch
            {   
                return answer;
            }
        }

        private int wasNumber;
        /// <summary>
        /// Checks if a string can be parsed as a valid number
        /// </summary>
        /// <param name="test">string to test</param>
        /// <returns>the true if the string was equivalent to a number</returns>
        public bool isNumeric(string test)
        {
            try
            {
                bool result = int.TryParse(test, out wasNumber);
                return result;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Checks if a string can be parsed as a valid tag
        /// </summary>
        /// <param name="test">string to test</param>
        /// <returns>the true if the string was equivalent to a tag</returns>
        public bool isDataTag(string test)
        {
            if (test.StartsWith("["))
            {
                if (test.EndsWith("]"))
                {
                    return true; // TODO: make sure that is a valid data tag
                }
            }
            return false;
        }


        /// <summary>
        /// Retrieves the absolute value of the difference between two numbers
        /// </summary>
        /// <param name="num1">first number</param>
        /// <param name="num2">seconds number</param>
        /// <returns>the absolute value of the difference between the two numbers</returns>
        public int Difference(int num1, int num2)
        {
            return Math.Abs(Math.Abs(num1) - Math.Abs(num2));
        }

        /// <summary>
        /// Retrieves the absolute value of the difference between two numbers
        /// </summary>
        /// <param name="num1">first number</param>
        /// <param name="num2">seconds number</param>
        /// <returns>the absolute value of the difference between the two numbers</returns>
        public float Difference(float num1, float num2)
        {
            return Math.Abs(Math.Abs(num1) - Math.Abs(num2));
        }


    }

}
